home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / OS / ODUtils / Sources / DlogUtil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-08  |  36.3 KB  |  1,405 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DlogUtil.cpp
  3.  
  4.     Contains:    implementation of dialog utility functions
  5.  
  6.     Owned by:    Tantek Çelik
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #ifndef _EXCEPT_
  13. #include <Except.h>
  14. #endif
  15.  
  16. #ifndef SOM_Module_OpenDoc_Errors_defined
  17. #include <ErrorDef.xh>
  18. #endif
  19.  
  20. #ifndef _DLOGUTIL_
  21. #include <DlogUtil.h>
  22. #endif
  23.  
  24. #ifndef _PLFMDEF_
  25. #include <PlfmDef.h>
  26. #endif
  27.  
  28. #ifndef _ODUTILS_
  29. #include <ODUtils.h>
  30. #endif
  31.  
  32. #ifndef SOM_ODMenuBar_xh
  33. #include <MenuBar.xh>
  34. #endif
  35.  
  36. #ifndef SOM_ODDispatcher_xh
  37. #include <Disptch.xh>
  38. #endif
  39.  
  40. #ifndef SOM_ODSession_xh
  41. #include <ODSessn.xh>
  42. #endif
  43.  
  44. #ifndef SOM_ODWindowState_xh
  45. #include <WinStat.xh>
  46. #endif
  47.  
  48. #ifndef SOM_ODClipboard_xh
  49. #include <Clipbd.xh>
  50. #endif
  51.  
  52. #ifndef _ODMEMORY_
  53. #include <ODMemory.h>
  54. #endif
  55.  
  56. #ifndef __GESTALTEQU__
  57. #include <GestaltEqu.h>
  58. #endif
  59.  
  60. #ifndef __TOOLUTILS__
  61. #include <ToolUtils.h>
  62. #endif
  63.  
  64. #ifndef _PASCLSTR_
  65. #include <PasclStr.h>
  66. #endif
  67.  
  68. #ifndef __DIALOGS__
  69. #include <Dialogs.h>
  70. #endif
  71.  
  72. #ifndef __TEXTEDIT__
  73. #include <TextEdit.h>
  74. #endif
  75.  
  76. #ifndef __PALETTES__
  77. #include <Palettes.h>
  78. #endif
  79.  
  80. #ifndef _MEMMGR_
  81. #include <MemMgr.h>
  82. #endif
  83.  
  84. #ifndef _ODDEBUG_
  85. #include <ODDebug.h>
  86. #endif
  87.  
  88. #ifndef _USERSRCM_
  89. #include <UseRsrcM.h>
  90. #endif
  91.  
  92. #ifndef SOM_ODNameSpaceManager_xh
  93. #include <NmSpcMg.xh>
  94. #endif
  95.  
  96. #ifndef SOM_Module_OpenDoc_Commands_defined
  97. #include <CmdDefs.xh>
  98. #endif
  99.  
  100. #ifndef SOM_ODStorageSystem_xh
  101. #include <ODStor.xh>
  102. #endif
  103.  
  104. #ifndef SOM_ODPlatformTypeList_xh
  105. #include <PfTypLs.xh>
  106. #endif
  107.  
  108. #ifndef _TEMPOBJ_
  109. #include "TempObj.h"
  110. #endif
  111.  
  112. // Types
  113. struct _MenuItemInfo
  114. {
  115.     MenuHandle    menu;
  116.     short        item;
  117.     Str255        text;
  118.     short        cmdChar;
  119.     short        iconID;
  120.     short        markChar;
  121.     Style        textStyle;
  122. };
  123. typedef struct _MenuItemInfo MenuItemInfo;
  124.  
  125. struct _DialogBoxInfo
  126. {
  127.     MenuItemInfo    redo;
  128.     // Can put other things in here later on
  129.     // like supporting movable modals, etc.
  130. };
  131. typedef struct _DialogBoxInfo DialogBoxInfo;
  132.  
  133. // Key codes
  134. // const char kEscapeKey        = 0x1B;
  135. // const char kUpArrowKey        = 0x1E;
  136. // const char kDownArrowKey    = 0x1F;
  137. const char kPageUpKey        = 0x0B;
  138. const char kPageDownKey        = 0x0C;
  139. const char kHomeKey            = 0x01;
  140. const char kEndKey            = 0x04;
  141.  
  142. // Control settings
  143. const short kControlInactive = 255;
  144. const short kControlActive = 0;
  145.  
  146. // Dialog item assumptions
  147. const short kOKButton = 1;
  148. const short kCancelButton = 2;
  149.  
  150. // Memory requirements
  151. const size_t kODMinFreeSpaceToShowDialog = 4 * 1024;
  152.     
  153. static Environment        *sEv;
  154. static ODSession        *sSession;
  155. static ModalFilterUPP    sFilter = kODNULL;
  156. static ModalFilterUPP    sButtonKeyFilter = kODNULL;
  157. static ModalFilterUPP    sArrowKeyFilter = kODNULL;
  158. static UserItemUPP        sOutlineDrawProc = kODNULL;
  159. static short            sCmdKeyStrResID = 0;    
  160. static DialogScriptData*
  161.                         sDlogScriptData = kODNULL;    
  162.     // Res ID of STR# that contains cmd-keys for buttons
  163.  
  164. static DialogBoxInfo* sDialogInfo = kODNULL;
  165.  
  166. // Private functions
  167. static void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem );
  168. static void RestoreMenuItem( MenuItemInfo *savedItem );
  169.  
  170.  
  171. //==============================================================================
  172. // Preflighting Dialogs and Alerts
  173. //==============================================================================
  174.  
  175. //------------------------------------------------------------------------------
  176. // Centering
  177. //------------------------------------------------------------------------------
  178.  
  179. static ODBoolean
  180. GetFrontWindowBounds( Rect &bounds )
  181. {
  182.     WindowPtr wp;
  183.     {
  184.         TempODWindow win = sSession->GetWindowState(sEv)->AcquireActiveWindow(sEv);
  185.         wp = win ? win->GetPlatformWindow(sEv) : FrontWindow();
  186.     }
  187.     
  188.     if( wp ) {
  189.         bounds = wp->portRect;
  190.         Rect *mapBounds;
  191.         if( wp->portBits.rowBytes & 0xC000 )            // Color port
  192.             mapBounds= &(**((CGrafPtr)wp)->portPixMap).bounds;
  193.         else
  194.             mapBounds= &wp->portBits.bounds;
  195.         OffsetRect(&bounds,-mapBounds->left,-mapBounds->top);
  196.         return kODTrue;
  197.     } else {
  198.         bounds = ODQDGlobals.screenBits.bounds;        // No win, use main screen
  199.         bounds.top += GetMBarHeight();
  200.         return kODFalse;
  201.     }
  202. }
  203.  
  204.  
  205. static void
  206. GetWindowsMainScreen( const Rect &windowBounds, Rect &screenBounds )
  207. {
  208.     long area=0;
  209.     
  210.     GDHandle gdh;
  211.     Rect devBounds,sectBounds;
  212.     long maxArea=0;
  213.     
  214.     for( gdh = GetDeviceList(); gdh; gdh = GetNextDevice(gdh) ) {
  215.         devBounds = (**gdh).gdRect;
  216.         if( gdh == GetMainDevice() )
  217.             devBounds.top += GetMBarHeight();
  218.         if( SectRect(&devBounds,&windowBounds,§Bounds) ) {
  219.             area = (sectBounds.right-sectBounds.left) * (long)(sectBounds.bottom-sectBounds.top);
  220.             if( area > maxArea ) {
  221.                 maxArea = area;                    // Best screen so far
  222.                 screenBounds = devBounds;
  223.                 if( gdh==GetMainDevice() )
  224.                     screenBounds.right -= 30;    // Leave room for Finder disk icons
  225.             }
  226.         }
  227.     }
  228.     if( area==0 ) {
  229.         screenBounds = ODQDGlobals.screenBits.bounds;        // Default: use main screen
  230.         screenBounds.top += GetMBarHeight();
  231.     }
  232. }
  233.  
  234.  
  235. static void
  236. CenterDialog( short ¢erFlag, Rect &bounds )
  237. {
  238.     /* Do centering manually. Why? Even though the Dialog Manager handles
  239.        automatic centering, it calls FrontWindow to find the parent window.
  240.        This will return an incorrect window (a floater) if there are floating
  241.        windows. We have to reproduce the centering effect but using the
  242.        actual frontmost non-floating window. */
  243.     const short noAutoCenter                    = 0x0000;
  244.     const short centerParentWindowScreen        = 0x680A;        // From Types.r
  245.     const short alertPositionParentWindowScreen = 0x700A;
  246.     const short centerParentWindow                = 0xA80A;
  247.     const short alertPositionParentWindow        = 0xB00A;
  248.     // We don't do anything for other flags.
  249.     
  250.     if( centerFlag == noAutoCenter )
  251.         return;
  252.     
  253.     Rect centerBounds;
  254.     if( GetFrontWindowBounds(centerBounds)
  255.             && (centerFlag==centerParentWindowScreen ||
  256.                 centerFlag==alertPositionParentWindowScreen) ) {
  257.         Rect screenBounds;
  258.         GetWindowsMainScreen(centerBounds,screenBounds);
  259.         centerBounds = screenBounds;
  260.     }
  261.     
  262.     Point pos;
  263.     pos.h = ((centerBounds.right-centerBounds.left)-(bounds.right-bounds.left)) >>1;
  264.     pos.v = ((centerBounds.bottom-centerBounds.top)-(bounds.bottom-bounds.top));
  265.     if( centerFlag==centerParentWindowScreen || centerFlag==centerParentWindow )
  266.         pos.v /= 2;
  267.     else if( centerFlag==alertPositionParentWindowScreen || centerFlag==alertPositionParentWindow )
  268.         pos.v /= 3;
  269.     else
  270.         return;                            // Ignore other flags
  271.         
  272.     pos.h += centerBounds.left;
  273.     pos.v += centerBounds.top;
  274.     OffsetRect(&bounds, pos.h-bounds.left, pos.v-bounds.top);
  275.     centerFlag = noAutoCenter;            // It's already centered now
  276. }
  277.  
  278.  
  279. //------------------------------------------------------------------------------
  280. // PreflightDialog
  281. //------------------------------------------------------------------------------
  282.  
  283. static Handle
  284. PreflightDialog( ODBoolean isDLOG, short id )
  285. {
  286.     Handle rsrc;
  287.     ODBoolean ok;
  288.     
  289.     if( isDLOG ) {
  290.         // Load DLOG and DITL:
  291.         rsrc = Get1Resource('DLOG', id);
  292.         DialogTemplate** dlogTemplate = (DialogTemplate**)rsrc;
  293.         ok = dlogTemplate && Get1Resource('DITL', (*dlogTemplate)->itemsID);
  294.         if( ok ) {
  295.             // Get the centering flag & adjust dialog centering:
  296.             HLock(rsrc);
  297.             size_t centerFlag = (size_t) &(**dlogTemplate).title;
  298.             centerFlag += *(unsigned char*)centerFlag +1;    // skip title
  299.             centerFlag += (centerFlag & 1);                    // word align
  300.             CenterDialog(*(short*)centerFlag, (**dlogTemplate).boundsRect);
  301.             HUnlock(rsrc);
  302.         }
  303.     } else {
  304.         // Load ALRT and DITL:
  305.         rsrc = Get1Resource('ALRT', id);
  306.         AlertTemplate** alrtTemplate = (AlertTemplate**)rsrc;
  307.         ok = alrtTemplate && Get1Resource('DITL', (*alrtTemplate)->itemsID);
  308.         if( ok ) {
  309.             // Get the centering flag & adjust alert centering:
  310.             HLock(rsrc);
  311.             short *centerFlag = (short*)( (size_t)*alrtTemplate + sizeof(AlertTemplate) );
  312.             CenterDialog(*centerFlag,(**alrtTemplate).boundsRect);
  313.             HUnlock(rsrc);
  314.         }
  315.     }
  316.     
  317.     if( !ok ) {
  318. #if ODDebug
  319.         OSErr err = ResError();
  320.         if( err != noErr && err != resNotFound )
  321.             WARN("Could not load dialog/alert %hd: error %hd",id,err);
  322. #endif
  323.         SysBeep(2);                            // At least give some indication
  324.         rsrc = kODNULL;
  325.     } else {
  326.         // Bail if space is really, really low. Don't even beep, this might cause
  327.         // a large 'snd' to be loaded.
  328.         if( !ODHaveFreeSpace(kODMinFreeSpaceToShowDialog,kODMinFreeSpaceToShowDialog,
  329.                              kODTrue) ) {
  330.             WARN("Whoa, not enough memory to show a dialog/alert!");
  331.             ReleaseResource(rsrc);
  332.             rsrc = kODNULL;
  333.         }
  334.     }
  335.     
  336.     return rsrc;
  337. }
  338.  
  339.  
  340. //==============================================================================
  341. // Displaying Dialogs and Alerts
  342. //==============================================================================
  343.  
  344. DialogPtr
  345. ODGetNewDialog( Environment *ev, short resID, ODSession *session, ODBoolean defaultButtons )
  346. {
  347.     ASSERT(session!=kODNULL, kODErrIllegalNullInput);
  348.  
  349.     sEv = ev ?ev :somGetGlobalEnvironment();
  350.     sSession = session;
  351.  
  352.     Handle dlogRsrc = PreflightDialog(kODTrue,resID);
  353.     if( ! dlogRsrc )
  354.         return kODNULL;
  355.  
  356.     DialogPtr dlog = ::GetNewDialog(resID,kODNULL,(WindowPtr)-1L);
  357.     if( dlog ) {
  358.         if( defaultButtons ) {
  359.             ::SetDialogDefaultItem(dlog,kStdOkItemIndex);
  360.             ::SetDialogCancelItem(dlog,kStdCancelItemIndex);
  361.         }
  362.         ::SetDialogTracksCursor(dlog,kODTrue);
  363.         
  364.         sCmdKeyStrResID = 0;    // Don't use command-key lookup unless told to
  365.         
  366.         InitCursor();            // Show arrow
  367.     }
  368.     
  369.     ReleaseResource(dlogRsrc);
  370.     
  371.     return dlog;
  372. }
  373.  
  374. ODSShort
  375. ShowAlert(Environment *ev, ODSShort alertID, ModalFilterUPP modalFilter, ODSession *session)
  376. {
  377.     ASSERT(session != kODNULL, kODErrIllegalNullInput);
  378.  
  379.     CUsingLibraryResources r;
  380.  
  381.     SetCursor(&(ODQDGlobals.arrow));
  382.  
  383.     sEv = ev ?ev :somGetGlobalEnvironment();
  384.     sSession = session;
  385.  
  386.     Handle alrtRsrc = PreflightDialog(kODFalse,alertID);
  387.     if( ! alrtRsrc )
  388.         return cancel;
  389.     
  390.     // Success at last!
  391.  
  392.     short alertReturn = Alert(alertID, modalFilter);
  393.     
  394.     ReleaseResource(alrtRsrc);
  395.  
  396.     return alertReturn;
  397. }
  398.  
  399. pascal Boolean
  400. ODDialogFilterProc( DialogPtr dp, EventRecord *event, short *item )
  401. {
  402.     ODBoolean dispatch = kODFalse;
  403.     
  404.     if( event->what==updateEvt || event->what==activateEvt ) {
  405.         if( (WindowPtr)event->message != dp )    // Dispatch updates/activates of other windows
  406.             dispatch = kODTrue;
  407.             
  408.     } else if( event->what==nullEvent || event->what==osEvt )    // Ditto null/suspend/resume
  409.         dispatch = kODTrue;
  410.     
  411.     else if( event->what==mouseDown ) {
  412.         WindowPtr wp;
  413.         if( ::FindWindow(event->where,&wp)==inDrag && wp==dp ) {    // Dragging me!
  414.             Rect bounds = ODQDGlobals.screenBits.bounds;
  415.             DragWindow(dp,event->where,&bounds);
  416.             event->what = nullEvent;
  417.         }
  418.         
  419.     } else if( event->what==keyDown ) {
  420.         // Cmd-A means select all if there is editable text:
  421.         short curTextItem = ((DialogPeek)dp)->editField + 1;
  422.         char key = event->message & charCodeMask;
  423.         if( curTextItem>0 && (key=='a' || key=='A') && (event->modifiers & cmdKey) )
  424.             SelectDialogItemText(dp, curTextItem, 0, 32767);
  425. #ifdef TO_BE_DELETED
  426.         else
  427.         {
  428.             long scriptNum = GetScriptManagerVariable( smKeyScript );
  429.             long curScript = FontToScript(dp->txFont);
  430.             if ( curScript != scriptNum )
  431.             {
  432. //                DebugStr( "\pChanging system font;g" );
  433.                 short myFont = GetScriptVariable( scriptNum, smScriptAppFond );
  434.                 WindowPtr savePort;
  435.                 GetPort(&savePort);
  436.                 SetPort(dp);
  437.                 TextFont( myFont );
  438.                 SetPort(savePort);
  439.             }
  440.         }
  441. #endif /* TO_BE_DELETED */
  442.     }
  443.     
  444.     if( dispatch ) {
  445.         TRY{
  446.             ODDispatcher* dispatcher = sSession->GetDispatcher(sEv);
  447.             if (dispatcher)
  448.                 dispatcher->Dispatch(sEv, (ODEventData*)event);
  449.         }CATCH_ALL{
  450.         }ENDTRY
  451.     }
  452.     
  453.     // Forward other events to the standard filter-proc:    
  454.     ModalFilterUPP proc;
  455.     OSErr err= GetStdFilterProc(&proc);
  456.     if( err==noErr )
  457.         return CallModalFilterProc(proc, dp,event,item);    // Call through to std filter-proc
  458.     else {
  459.         WARN("Couldn't get std filter proc!");
  460.         return false;
  461.     }
  462. }
  463.  
  464.  
  465. ModalFilterUPP
  466. GetODDialogFilter( )
  467. {
  468.     if( !sFilter )
  469.         sFilter = NewModalFilterProc(&ODDialogFilterProc);
  470.     return sFilter;
  471. }
  472.  
  473.  
  474. //==============================================================================
  475. // Filter Procs & Such
  476. //==============================================================================
  477.  
  478. static void
  479. ActivateControl(DialogPtr dialog, short item, Boolean isActivate)
  480. {
  481.     short            itemType;
  482.     Rect            itemRect;
  483.     ControlHandle    cntrlHandle;
  484.  
  485.     GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  486.     ASSERT_CONTROL_ITEM(itemType);
  487.     
  488.     CUsingLibraryResources r;
  489.  
  490.     if ( isActivate )
  491.     {
  492.         HiliteControl(cntrlHandle, GetControlReference(cntrlHandle));
  493.     }
  494.     else
  495.     {
  496.         SetControlReference(cntrlHandle, (**cntrlHandle).contrlHilite);
  497.         HiliteControl(cntrlHandle, kControlInactive);
  498.     }
  499. }
  500.  
  501. static void
  502. ActivateAllControls(DialogPtr dialog, Boolean isActivate)
  503. {
  504.     short            itemType;
  505.     Rect            itemRect;
  506.     ControlHandle    cntrlHandle;
  507.     short            item;
  508.  
  509.     for (item = 1; item <= CountDITL(dialog); ++item)
  510.     {
  511.         GetDialogItem(dialog, item, &itemType, (Handle*) &cntrlHandle, &itemRect);
  512.         itemType &= ~kItemDisableBit;
  513.         if ( itemType>=ctrlItem && itemType<=ctrlItem+resCtrl )
  514.             ActivateControl(dialog, item, isActivate);
  515.     }
  516. }
  517.  
  518.  
  519. pascal Boolean ODArrowKeyFilterProc( DialogPtr dlg, ODEventData* event,
  520.         short* itemHit )
  521. {
  522.     Boolean result;
  523.     if ( event->what == keyDown || event->what == autoKey )
  524.     {
  525.         result = kODTrue;
  526.         char key = event->message & charCodeMask;
  527.         ODBoolean cmdKeyDown = (event->modifiers & cmdKey) != 0;
  528.         ODBoolean optionKeyDown = (event->modifiers & optionKey) != 0;
  529.         switch ( key )
  530.         {
  531.             case kUpArrowKey:
  532.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODHomeArrowItem :
  533.                         kODPageUpArrowItem : kODUpArrowItem;
  534.                 break;
  535.             case kDownArrowKey:
  536.                 *itemHit = cmdKeyDown ? optionKeyDown ? kODEndArrowItem :
  537.                         kODPageDownArrowItem : kODDownArrowItem;
  538.                 break;
  539.  
  540.             case kPageUpKey:
  541.                 *itemHit = kODPageUpArrowItem;
  542.                 break;
  543.             case kPageDownKey:
  544.                 *itemHit = kODPageDownArrowItem;
  545.                 break;
  546.             case kHomeKey:
  547.                 *itemHit = kODHomeArrowItem;
  548.                 break;
  549.             case kEndKey:
  550.                 *itemHit = kODEndArrowItem;
  551.                 break;
  552.  
  553.             default:
  554.                 result = kODFalse;
  555.         }
  556.     }
  557.     else
  558.         result = kODFalse;
  559.     return result || ODButtonKeyFilterProc( dlg, event, itemHit );
  560. }
  561.  
  562.  
  563. ModalFilterUPP
  564. GetODArrowKeyFilterProc( )
  565. {
  566.     if( !sArrowKeyFilter )
  567.         sArrowKeyFilter = NewModalFilterProc(&ODArrowKeyFilterProc);
  568.     return sArrowKeyFilter;
  569. }
  570.  
  571. // DMc: this debugging code disables use of enter to mean 'OK' when this var is set:
  572. // #if ODDebug
  573. // int gODButtonKeyNoEnterOkay = 0; // set to non-zero to disable enter for okay
  574. // #endif
  575.  
  576. pascal Boolean
  577. ODButtonKeyFilterProc(DialogPtr dialog, EventRecord *event, short *itemHit)
  578. {    
  579.     Rect            itemRect;
  580.     short            itemType;
  581.     Handle            itemHandle;
  582.     short            myItemHit = 0;
  583.  
  584.     const short        kEscKeyCode = 0x35;    // Virtual key code for the escape key
  585.  
  586.     if ( event->what == keyDown )
  587.     {
  588.         char key = event->message & charCodeMask;
  589.         switch ( key )
  590.         {
  591.             case kReturnKey:
  592.             case kEnterKey:
  593.                 GetDialogItem(dialog, kOKButton, &itemType, &itemHandle, &itemRect);
  594.                 ASSERT_CONTROL_ITEM(itemType);
  595.  
  596. // DMc: this debugging code disables use of enter to mean 'OK' when a var is set:
  597. // #if ODDebug
  598. //                 if ( !gODButtonKeyNoEnterOkay || key != kEnterKey )
  599. //                 {
  600. //                     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  601. //                         myItemHit = kOKButton;
  602. //                 }
  603. // #else
  604.                 if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  605.                     myItemHit = kOKButton;
  606. // #endif /*ODDebug*/
  607.                     
  608.                 break;
  609.             
  610.             case kEscapeKey:
  611.                 // Ensure that the escape key, not the clear key, was pressed
  612.                 if ( (event->message & keyCodeMask) == (kEscKeyCode << 8) )
  613.                 {
  614.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  615.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  616.                         myItemHit = kCancelButton;
  617.                 }
  618.                 break;
  619.  
  620.             case '.':        // cmd-period means cancel
  621.                 if ( event->modifiers & cmdKey )
  622.                 {
  623.                     GetDialogItem(dialog, kCancelButton, &itemType, &itemHandle, &itemRect);
  624.                     if ( (itemType & ~kItemDisableBit) == (ctrlItem+btnCtrl) )
  625.                         myItemHit = kCancelButton;
  626.                 }
  627.                 break;
  628.  
  629.             default:
  630.                 if ( (sCmdKeyStrResID != 0)  && (event->modifiers & cmdKey) )
  631.                 {
  632.                     // Attempt to match the key to a key found in the STR# resource
  633.                     Handle stringsHandle = GetResource( 'STR#', sCmdKeyStrResID );
  634.                     if ( stringsHandle )
  635.                     {
  636.                         short     i;
  637.                         short    numStrings = **(short**)stringsHandle;
  638.                         Str255    cmdKeyCode;
  639.                         for ( i = 1; i <= numStrings; ++i )
  640.                         {
  641.                           GetIndString( cmdKeyCode, sCmdKeyStrResID, i );
  642.                           if ( cmdKeyCode[0] && cmdKeyCode[1] == key )
  643.                           {
  644.                             GetDialogItem(dialog, i, &itemType, &itemHandle, &itemRect);
  645.                             ASSERT_CONTROL_ITEM(itemType);
  646.                             if ( (**(ControlHandle)itemHandle).contrlHilite == kControlActive )
  647.                             {
  648.                               myItemHit = i;    // Cool--record the item number that is hit
  649.                               break;
  650.                             }
  651.                           }
  652.                         }
  653.                     } 
  654.                 }
  655.                 break;
  656.         }
  657.  
  658.         if ( myItemHit != 0 )    // need to hilite a button
  659.         {
  660.             FlashButtonItem( dialog, myItemHit );
  661.             *itemHit = myItemHit;
  662.             return kODTrue;
  663.         }
  664.     
  665.     }
  666.     else if ( event->what == activateEvt )
  667.     {
  668.         Boolean isActivate = ((event->modifiers & activeFlag) != 0 );
  669.         ActivateAllControls(dialog, isActivate);
  670.     }
  671.  
  672.     // we only get here if we'd otherwise be returning false; all successes
  673.     // exit at "return kODTrue" above
  674.     return ODDialogFilterProc(dialog,event,itemHit);
  675. }
  676.  
  677.  
  678. ModalFilterUPP
  679. GetODButtonKeyFilterProc( )
  680. {
  681.     if( !sButtonKeyFilter )
  682.         sButtonKeyFilter = NewModalFilterProc(&ODButtonKeyFilterProc);
  683.     return sButtonKeyFilter;
  684. }
  685.  
  686.  
  687. void
  688. ODUseCommandKeyStringsResource( short resID )
  689. {
  690.     sCmdKeyStrResID = resID;
  691. }
  692.  
  693.  
  694. //==============================================================================
  695. // Updating the Menu Bar
  696. //==============================================================================
  697.  
  698. void ODDialogBegin( Environment* ev, ODSession* session, 
  699.             ODMenuBar* currentMenuBar, DialogPtr dialog )
  700. {
  701.     ODUnused(dialog);    // Later on, we can use this to support movable modals
  702.     
  703.     if ( sEv == kODNULL )
  704.         sEv = ev;
  705.  
  706.     if ( sSession == kODNULL )
  707.         sSession = session;
  708.  
  709.     ASSERT(currentMenuBar!=kODNULL,kODErrIllegalNullInput);
  710.     ASSERT(sSession!=kODNULL,kODErrIllegalNullInput);
  711.     
  712.     // Cleanup if needed
  713.     if ( sDialogInfo )
  714.         ODDisposePtr(sDialogInfo);
  715.  
  716.     // Allocate a new menu info record
  717.     sDialogInfo = (DialogBoxInfo*)ODNewPtrClear(sizeof(DialogBoxInfo),kDefaultHeapID);
  718.  
  719.     if ( sDialogInfo )
  720.     {
  721.         ODMenuID        editMenuID = 0;
  722.         ODPlatformMenu    editMenu = kODNULL;
  723.         short            redoItem;
  724.  
  725.         // Delete the Redo menu item so ModalDialog will handle the Edit menu right.
  726.         currentMenuBar->GetMenuAndItem(sEv, kODCommandRedo, &editMenuID, &redoItem);
  727.         editMenu = currentMenuBar->GetMenu(sEv, editMenuID );
  728.         if ( editMenu )
  729.             SaveAndDeleteMenuItem(editMenu, redoItem, &sDialogInfo->redo);
  730.         else
  731.         {
  732.             ODDisposePtr(sDialogInfo);
  733.             sDialogInfo = kODNULL;
  734.         }
  735.     }
  736.     
  737.     // Lastly, export the OD clipboard in case the user pastes into the dialog
  738.     ODPlatformTypeList* types = session->GetStorageSystem(ev)->CreatePlatformTypeList(ev, kODNULL);
  739.     types->AddLast(sEv, 'TEXT');
  740.     types->AddLast(sEv, 'PICT');
  741.     sSession->GetClipboard(sEv)->SetPlatformClipboard(sEv, types);
  742.     ODDeleteObject(types);
  743. }
  744.  
  745.  
  746. void ODDialogEnd()
  747. {
  748.     // Restore the Redo menu item deleted by DialogBegin
  749.     if ( sDialogInfo )
  750.     {
  751.         RestoreMenuItem(&sDialogInfo->redo);
  752.         ODDisposePtr(sDialogInfo);
  753.         sDialogInfo = kODNULL;        // Don't allow to be called again
  754.     }
  755. }
  756.  
  757.  
  758. void SaveAndDeleteMenuItem( MenuHandle menu, short item, MenuItemInfo *savedItem )
  759. {
  760.     savedItem->menu = menu;
  761.     savedItem->item = item;
  762.     GetMenuItemText(menu, item, savedItem->text);
  763.     GetItemCmd(menu, item, &savedItem->cmdChar);
  764.     GetItemIcon(menu, item, &savedItem->iconID);
  765.     GetItemMark(menu, item, &savedItem->markChar);
  766.     GetItemStyle(menu, item, &savedItem->textStyle);
  767.     DeleteMenuItem(menu, item);
  768.     InvalMenuBar();
  769. }
  770.  
  771.  
  772. void RestoreMenuItem( MenuItemInfo *savedItem )
  773. {
  774.     InsertMenuItem(savedItem->menu, savedItem->text, savedItem->item -1);
  775.         // Still set item text in case of non-meta meta-characters.
  776.     SetMenuItemText(savedItem->menu, savedItem->item, savedItem->text);
  777.     SetItemCmd(savedItem->menu, savedItem->item, savedItem->cmdChar);
  778.     SetItemIcon(savedItem->menu, savedItem->item, savedItem->iconID);
  779.     SetItemMark(savedItem->menu, savedItem->item, savedItem->markChar);
  780.     SetItemStyle(savedItem->menu, savedItem->item, savedItem->textStyle);
  781.     InvalMenuBar();
  782. }
  783.  
  784.  
  785. pascal void
  786. ODOutlineDefaultButtonDrawProc(DialogPtr theDialog, short theItem)
  787. {
  788.     Rect         itemRect;
  789.     Handle        itemHandle;
  790.     short        itemKind;
  791.  
  792.     WindowPtr    buttonWindow;
  793.     WindowPtr    savePort;
  794.     PenState    savePen;
  795.     short        buttonOval;
  796.     Boolean        isColorPort;
  797.  
  798.     const short kColorPort = 0xC000;
  799.  
  800.     GetDialogItem(theDialog, kOKButton, &itemKind, &itemHandle, &itemRect);
  801.     ASSERT_CONTROL_ITEM(itemKind);
  802.  
  803.     GetPort(&savePort);
  804.     buttonWindow = (**(ControlHandle)itemHandle).contrlOwner;
  805.     SetPort(buttonWindow);
  806.     GetPenState(&savePen);
  807.     PenNormal();
  808.  
  809.     InsetRect(&itemRect, -4, -4);
  810.     FrameRoundRect(&itemRect, 16, 16);
  811.     buttonOval = ((itemRect.bottom - itemRect.top)/2)+2;
  812.  
  813.     isColorPort = ((((CGrafPtr)buttonWindow)->portVersion & kColorPort) == kColorPort);
  814.     
  815.     if ( (**(ControlHandle)itemHandle).contrlHilite == kControlInactive )
  816.     {
  817.         // Button is inactive, so outline with gray
  818.  
  819.         RGBColor    fgSaveColor;
  820.         RGBColor    fgNewColor;
  821.         RGBColor    bgColor;
  822.         Boolean        newGray = false;
  823.  
  824.         if ( isColorPort )
  825.         {
  826.             GetBackColor(&bgColor);
  827.             GetForeColor(&fgSaveColor);
  828.             fgNewColor = fgSaveColor;
  829.             
  830.             Rect globalRect = itemRect;
  831.             LocalToGlobal((Point *)&(globalRect.top));
  832.             LocalToGlobal((Point *)&(globalRect.bottom));
  833.             GDHandle targetDevice = GetMaxDevice(&globalRect);
  834.             
  835.             newGray = GetGray(targetDevice, &bgColor, &fgNewColor);
  836.         }
  837.  
  838.         if ( newGray )
  839.             RGBForeColor(&fgNewColor);
  840.         else
  841. #ifdef THINK_CPLUS
  842.             PenPat(ODQDGlobals.gray);
  843. #else
  844.             PenPat(&ODQDGlobals.gray);
  845. #endif
  846.  
  847.         PenSize(3, 3);
  848.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  849.         
  850.         if ( isColorPort )
  851.             RGBForeColor(&fgSaveColor);
  852.     }
  853.     else
  854.     {
  855.         // Button is active, so outline with black
  856. #ifdef THINK_CPLUS
  857.         PenPat(ODQDGlobals.black);
  858. #else
  859.         PenPat(&ODQDGlobals.black);
  860. #endif
  861.         PenSize(3, 3);
  862.         FrameRoundRect(&itemRect, buttonOval, buttonOval);
  863.     }
  864.  
  865.     SetPenState(&savePen);
  866.     SetPort(savePort);
  867. }
  868.  
  869.  
  870. UserItemUPP
  871. GetODOutlineDefaultButtonDrawProc( )
  872. {
  873.     if( !sOutlineDrawProc )
  874.         sOutlineDrawProc = NewUserItemProc(&ODOutlineDefaultButtonDrawProc);
  875.     return sOutlineDrawProc;
  876. }
  877.  
  878.  
  879. void
  880. ODUseDialogScriptData( DialogScriptData* dsd, DialogPtr dialog )
  881. {
  882.     sDlogScriptData = dsd;
  883.     dsd->SetDialog( dialog );
  884. }
  885.  
  886. pascal ODBoolean CheckKeyScriptChangeFilterProc( DialogPtr dialog,
  887.         EventRecord *event, short *itemHit)
  888. {
  889.     TEHandle teh = ((DialogPeek)dialog)->textH;
  890.     DialogScriptData* dsd = sDlogScriptData;
  891.     WASSERT( dsd );
  892.  
  893.     if ( dsd->Script() == ksmUninited )
  894.         dsd->SetScriptAndLockKeyboard();
  895.  
  896.     if ( event->what == keyDown )
  897.     {
  898.         if ( !dsd->ScriptChanged() )
  899.         {
  900.             ODScriptCode newScript = GetScriptManagerVariable(smKeyScript);
  901.             ODScriptCode fontScript = FontToScript((*teh)->txFont);
  902.             WASSERT( fontScript == dsd->Script() );
  903.             if ( fontScript != newScript )
  904.             {
  905.                 short newFont = GetScriptVariable( newScript, smScriptAppFond );
  906.                 (*teh)->txFont = newFont;
  907. //                TextFont(newFont);
  908.  
  909.                 dsd->SetScriptAndLockKeyboard( FontToScript(newFont) );
  910.             }
  911.         }
  912.     }
  913.  
  914.     // if this is the first time in this edit item, redraw in case
  915.     // we've switched fonts/scripts.
  916.     short currentItem = ((DialogPeek)dialog)->editField;
  917.     if ( dsd->ScriptChanged() && !dsd->ItemRedrawn(currentItem) )
  918.     {
  919.         dsd->SetRedrawn(currentItem);
  920.         short itemKind;
  921.         Handle ignoreH;
  922.         Rect ignoreR;
  923.         GetDialogItem( dialog, currentItem+1, &itemKind, &ignoreH, &ignoreR );
  924.         if ( itemKind == editText )
  925.         {
  926.             TECalText( teh );
  927.             Rect viewRect = (*teh)->viewRect;
  928.             TEUpdate( &viewRect, teh );
  929.         }
  930.     }
  931.  
  932.     // pass to the next filter proc.  This one just changes state, never
  933.     // consuming the event.
  934.     return kODFalse;
  935. }
  936.  
  937. void EnableOkButton(DialogPtr dlog, ODBoolean enable)
  938. {
  939.     Environment*    ev = somGetGlobalEnvironment();
  940.     short            itemType;
  941.     Handle            itemHandle;
  942.     Rect            itemRect;
  943.     ODBoolean        okEnabled;
  944.  
  945.     const short kButtonFrameInset = -4;
  946.  
  947.     GetDialogItem(dlog, kOKButton, &itemType, &itemHandle, &itemRect);    
  948.     ASSERT_CONTROL_ITEM(itemType);
  949.     okEnabled = (**(ControlHandle)itemHandle).contrlHilite == kControlActive;
  950.  
  951.     // there's nothing to do if the button is as it should be already
  952.     if ( enable != okEnabled )
  953.     {
  954.         HiliteControl((ControlHandle)itemHandle, enable ? kControlActive : kControlInactive);
  955.  
  956.         // Invalidate the default button frame so it will be redrawn dim
  957.         WindowPtr savePort;
  958.         GetPort(&savePort);
  959.         SetPort(dlog);
  960.         InsetRect(&itemRect, kButtonFrameInset, kButtonFrameInset);
  961.         InvalRect(&itemRect);
  962.         SetPort(savePort);
  963.     }
  964. }
  965.  
  966. //    DrawGrayBox draws a gray box to be used as a separator.
  967. //    On a ColorQD machine, a true-gray line is attempted.
  968. //  On a B&W machine, a 50% pattern is used.
  969.  
  970. static pascal void DrawGrayBox(Rect *theBox)
  971. {
  972.     PenState    penState;
  973.     GetPenState(&penState);
  974.  
  975.     PixPatHandle ppat = kODNULL;
  976.     
  977.     /* check if Color QuickDraw is available */    
  978.     long response;
  979.     if( Gestalt(gestaltQuickdrawFeatures, &response)==noErr
  980.                 && BitTst(&response, 31-gestaltHasColor) ) {
  981.         const RGBColor gray = {0x7FFF,0x7FFF,0x7FFF};
  982.         ppat = NewPixPat();
  983.         if( ppat )
  984.             MakeRGBPat(ppat,&gray);
  985.     }
  986.  
  987.     if( ppat )
  988.         PenPixPat(ppat);
  989.     else
  990.         PenPat(&ODQDGlobals.gray);
  991.         
  992.     FrameRect(theBox);
  993.     
  994.     SetPenState(&penState);
  995.  
  996.     if( ppat )
  997.         DisposePixPat(ppat);
  998. }
  999.  
  1000. pascal void DrawGrayBoxItem(DialogPtr theDialog, short theItem)
  1001. {
  1002.     Rect     boxRect;
  1003.     Handle    scratchHandle;
  1004.     short    scratchKind;
  1005.     
  1006.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &boxRect);
  1007.     DrawGrayBox(&boxRect);
  1008. }
  1009.  
  1010. pascal void DrawItemFrame(DialogPtr theDialog, short theItem)
  1011. {
  1012.     Rect     frameRect;
  1013.     Handle    scratchHandle;
  1014.     short    scratchKind;
  1015.     
  1016.     GetDialogItem(theDialog, theItem, &scratchKind, &scratchHandle, &frameRect);
  1017.     FrameRect(&frameRect);
  1018. }
  1019.  
  1020. ////////////////////////////////////////////////////////////////////////////////
  1021. // DrawITextInDlogBox
  1022. // Given a dialog, a rect and an ODIText*, truncate the text to fit in the
  1023. // rect and then draw it in the dialog.  Return result telling whether any
  1024. // change was made.
  1025. ////////////////////////////////////////////////////////////////////////////////
  1026.  
  1027. ODBoolean DrawITextInDlogBox( ODIText* itext, const Rect* textRect,
  1028.         DialogPtr dlog, ODBoolean tryToTruncate )
  1029. {
  1030.     WASSERT(dlog);
  1031.     WindowPtr savePort;
  1032.     GetPort(&savePort);
  1033.     SetPort(dlog);
  1034.  
  1035.     PenState savedPenState;
  1036.     GetPenState(&savedPenState);
  1037.     PenNormal();
  1038.  
  1039.     short saveFont = dlog->txFont;
  1040.     short savedTextMode = dlog->txMode;
  1041.     
  1042.     ODScriptCode scriptCode = GetITextScriptCode(itext);
  1043.     if ( scriptCode != FontToScript(saveFont) )
  1044.         TextFont(GetScriptVariable(scriptCode,smScriptAppFond));
  1045.     
  1046.     char buffer[256];
  1047.     ODSShort len = GetITextStringLength(itext);
  1048.     if ( len > 255 ) len = 255;
  1049.     ODBlockMove( GetITextPtr( itext ), buffer, len );
  1050.     short truncResult;
  1051.     if ( tryToTruncate )
  1052.         truncResult = TruncText( textRect->right - textRect->left - 1,
  1053.             buffer, &len, truncEnd);
  1054.     TETextBox( buffer, len,    textRect, teFlushDefault );
  1055.  
  1056.     TextFont(saveFont);
  1057.     TextMode(savedTextMode);
  1058.     SetPenState(&savedPenState);
  1059.     SetPort(savePort);
  1060.     return tryToTruncate? truncResult == 1 : kODFalse;    // 1 means truncation needed and successful
  1061. }
  1062.  
  1063. ////////////////////////////////////////////////////////////////////////////////
  1064. // FlashButtonItem
  1065. // Given a dialog and an item representing a button, flash that button,
  1066. // highlighting it for 8 ticks and then reverting.
  1067. ////////////////////////////////////////////////////////////////////////////////
  1068. void FlashButtonItem( DialogPtr dialog, short itemHit )
  1069. {
  1070.     Rect itemRect;
  1071.     short itemType;
  1072.     Handle itemHandle;
  1073.  
  1074.     GetDialogItem( dialog, itemHit, &itemType, &itemHandle, &itemRect);
  1075.     ASSERT_CONTROL_ITEM(itemType);
  1076.     HiliteControl((ControlHandle)itemHandle, kControlButtonPart);
  1077.     unsigned long ticks = TickCount() + 8;
  1078.     while ( TickCount() < ticks ) ;
  1079.     HiliteControl((ControlHandle)itemHandle, kControlActive);    // Turn off hilite
  1080. }
  1081.  
  1082. ////////////////////////////////////////////////////////////////////////////////
  1083. // ArrowKeyScrollList
  1084. // Given an "item" representing an up or down arrow or any of the other keys
  1085. // recognized by ODArrowKeyFilterProc above, a ListHandle indicating the list
  1086. // in which scrolling is taking place, pageSize giving the number of entries to
  1087. // be skipped by a "page down" command, and the zero-based index of the last
  1088. // entry in the list, do the right thing for the key selected.  So far this
  1089. // routine is used for lists embedded in dialogs, and it's up to the caller
  1090. // to determine which list is meant if there is more than one.
  1091. // NOTE that nothing happens currently if no list item is selected.  There needs
  1092. // to be a starting point for scrolling.
  1093. ////////////////////////////////////////////////////////////////////////////////
  1094.  
  1095. void ArrowKeyScrollList( ODSShort arrowItem, ListHandle listH,
  1096.         ODSShort pageSize, ODSShort lastEntry )
  1097. {
  1098.     ODSShort limitCell;
  1099.     ODSShort delta;
  1100.     switch( arrowItem )
  1101.     {
  1102.         case kODUpArrowItem:
  1103.             limitCell = 0;
  1104.             delta = -1;
  1105.             break;
  1106.  
  1107.         case kODDownArrowItem:
  1108.             limitCell = lastEntry;
  1109.             delta = 1;
  1110.             break;
  1111.  
  1112.         case kODPageUpArrowItem:
  1113.             limitCell = 0;
  1114.             delta = 0 - pageSize;
  1115.             break;
  1116.  
  1117.         case kODPageDownArrowItem:
  1118.             limitCell = lastEntry;
  1119.             delta = pageSize;
  1120.             break;
  1121.  
  1122.         case kODHomeArrowItem:
  1123.             limitCell = 0;
  1124.             delta = 0 - lastEntry;
  1125.             break;
  1126.  
  1127.         case kODEndArrowItem:
  1128.             limitCell = lastEntry;
  1129.             delta = lastEntry;
  1130.             break;
  1131.  
  1132.         default:
  1133.             WARN( "unknown arrow key/item" );
  1134.             return;
  1135.     }
  1136.  
  1137.     Cell selectedCell = {0,0};
  1138.     if ( !LGetSelect( true, &selectedCell, listH ) 
  1139.             || (selectedCell.v == limitCell) ) 
  1140.         return;
  1141.     LSetSelect( false, selectedCell, listH );
  1142.     selectedCell.v += delta;
  1143.     if ( selectedCell.v < 0 )
  1144.         selectedCell.v = 0;
  1145.     else if ( limitCell > 0 && selectedCell.v > limitCell )
  1146.         selectedCell.v = limitCell;
  1147.     LSetSelect( true, selectedCell, listH );
  1148.     LAutoScroll(listH);
  1149. }
  1150.  
  1151. //------------------------------------------------------------------------------
  1152. // ReplaceIntoString
  1153. //------------------------------------------------------------------------------
  1154. // Substitutes str0 for all occurances of "^0", and str1 for "^1", in the string
  1155. // retrieved from the 'STR ' resource identified by the first parameter.  Either
  1156. // str0 or str1 may be null.  Uses the current resource chain to find the 'STR '
  1157. // resource.
  1158.  
  1159. void ReplaceIntoString(ODSShort strResourceID,
  1160.                         ConstStr255Param str0,
  1161.                         ConstStr255Param str1,
  1162.                         Str255 destString)
  1163. {
  1164.     StringHandle msgHandle = GetString(strResourceID);
  1165.     if ( msgHandle )
  1166.     {
  1167.         DetachResource((Handle) msgHandle);
  1168.  
  1169.         ODHandle textHandle;
  1170.  
  1171.         HLock((Handle) msgHandle);
  1172.         ODHandle templateText = PStrToText(*msgHandle);
  1173.         HUnlock((Handle) msgHandle);
  1174.  
  1175.         if ( str0 )
  1176.         {
  1177.             textHandle = PStrToText(str0);
  1178.             if ( textHandle )
  1179.             {
  1180.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^0");
  1181.                 ODDisposeHandle(textHandle);
  1182.             }
  1183.         }
  1184.         
  1185.         if ( str1 )
  1186.         {
  1187.             textHandle = PStrToText(str1);
  1188.             if ( textHandle )
  1189.             {
  1190.                 ReplaceText((Handle) templateText, (Handle) textHandle, "\p^1");
  1191.                 ODDisposeHandle(textHandle);
  1192.             }
  1193.         }
  1194.  
  1195.         TextToPStr(templateText, destString);
  1196.  
  1197.         ODDisposeHandle(templateText);
  1198.         DisposeHandle((Handle) msgHandle);
  1199.     }
  1200.     else
  1201.         if( ResError() != memFullErr )
  1202.         {
  1203.             WARN("ReplaceIntoString didn't find STR %hd",strResourceID);
  1204.             destString[0] = 0;
  1205.         }
  1206. }
  1207.  
  1208.  
  1209. //--------------------------------------------------------------------
  1210. // GetODITextInd
  1211. // Gets string # (index) from the 'STR#' resource given by resID 
  1212. // into an IText* whose script and language codes are those of 
  1213. // the current system script.
  1214. //--------------------------------------------------------------------
  1215.  
  1216. ODIText* GetODITextInd(short resID, short index)
  1217. {
  1218.     Str255 pStr = "\p";
  1219.     GetIndString(pStr, resID, index);
  1220.     ODScriptCode script = FontToScript( GetSysFont() );
  1221.     return CreateITextPString(script,
  1222.                             GetScriptVariable(script, smScriptLang), 
  1223.                             pStr);
  1224. }
  1225.  
  1226.  
  1227. //--------------------------------------------------------------------
  1228. // GetODIText
  1229. // Turns an 'STR ' resource of the given resID into an ODIText* whose
  1230. // language and script codes are those of the current system script.
  1231. //--------------------------------------------------------------------
  1232.  
  1233. ODIText* GetODIText(short resID)
  1234. {
  1235.     Handle textHandle;
  1236.     ODIText* iText = kODNULL;
  1237.     
  1238.     textHandle = (Handle)GetString(resID);
  1239.     
  1240.     if ( textHandle != kODNULL )
  1241.     {
  1242.         // CreateIText copies the values passed into it, so we don't
  1243.         // have to worry about the resource handle moving outside of
  1244.         // the scope of this function.
  1245.  
  1246.         ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1247.         ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1248.         HLock(textHandle);
  1249.         iText = CreateIText( script, lang, (StringPtr)*textHandle );
  1250.             
  1251.         ReleaseResource(textHandle);
  1252.     }
  1253.     
  1254.     return iText;
  1255. }
  1256.  
  1257. //------------------------------------------------------------------------------
  1258. // SetDialogTextStyle
  1259. //------------------------------------------------------------------------------
  1260.  
  1261. void SetDialogTextStyle(DialogPtr dlg, short finfResourceID,
  1262.         ODScriptCode script)
  1263. {
  1264.     typedef struct {
  1265.         short count;
  1266.         short fontNumber;
  1267.         short fontStyl;
  1268.         short fontSize;
  1269.     } FontSpec;
  1270.  
  1271.     typedef FontSpec** FontSpecHandle;
  1272.     
  1273.     FontSpecHandle finfHandle = (FontSpecHandle) GetResource('finf', finfResourceID);
  1274.  
  1275.     if ( finfHandle )
  1276.     {
  1277.         SetPort(dlg);
  1278.         
  1279.         short font;
  1280.         if ( script != smCurrentScript )
  1281.             font = GetScriptVariable( script, smScriptAppFond );    // <eeh> smScriptSysFond better?
  1282.         else
  1283.             font = (**finfHandle).fontNumber;
  1284.         
  1285.         TextFont(font);
  1286.         TextFace((**finfHandle).fontStyl);
  1287.         TextSize((**finfHandle).fontSize);
  1288.         TEHandle te = ((DialogPeek)dlg)->textH;
  1289.         (**te).txFont = font;
  1290.         (**te).txSize = (**finfHandle).fontSize;
  1291.         (**te).txFace = (**finfHandle).fontStyl;
  1292.         TECalText(te);
  1293.         ReleaseResource((Handle) finfHandle);
  1294.     } else
  1295.         if( ResError() != memFullErr )
  1296.             WARN("SetDialogTextStyle didn't find 'finf' %hd",finfResourceID);
  1297. }
  1298.  
  1299. //-------------------------------------------------------------------------------------
  1300. // SetPopupItemScript
  1301. //-------------------------------------------------------------------------------------
  1302. // "scriptID" should be a true script code, not an implicit script code
  1303. //
  1304. // This routine assumes the popup is drawn using the font of the current port.
  1305. //
  1306. // Setting the script of a popup menu item has two bad consequences:
  1307. // The title and item appear in bold face, and the width of the
  1308. // menu is increased.  This is true even if the script specified
  1309. // is the same as the default script!  So only specify a script if its different.
  1310.  
  1311. void SetPopupItemScript(MenuHandle menu, short itemNum, short scriptID)
  1312. {
  1313.     const ODSShort kUseSpecificScript = 0x1c;
  1314.  
  1315.     ODSLong    savedSMFontForceFlag = GetScriptManagerVariable(smFontForce);
  1316.     SetScriptManagerVariable(smFontForce, false);
  1317.  
  1318.     // Since the popup is drawn using the window font, compare the argument
  1319.     // script to the script of the current graphics port.
  1320.     GrafPtr curPort;
  1321.     GetPort(&curPort);
  1322.  
  1323.     if ( scriptID == smSystemScript )
  1324.         scriptID = (short) GetScriptManagerVariable(smSysScript);
  1325.  
  1326.     if ( scriptID != FontToScript(curPort->txFont) )
  1327.     {
  1328.         SetItemCmd(menu, itemNum, kUseSpecificScript);
  1329.         SetItemIcon(menu, itemNum, scriptID);
  1330.     }
  1331.     
  1332.     SetScriptManagerVariable(smFontForce, savedSMFontForceFlag);
  1333. }
  1334.  
  1335.  
  1336. //-------------------------------------------------------------------------------------
  1337. // Implementation of DialogScriptData class
  1338. //-------------------------------------------------------------------------------------
  1339.  
  1340. DialogScriptData::DialogScriptData()
  1341. {
  1342.     fItemRedrawn = 0L;
  1343.     fMustUnlock = kODFalse;
  1344.     fScript = ksmUninited;
  1345. }
  1346.  
  1347. DialogScriptData::~DialogScriptData()
  1348. {
  1349.     if ( fMustUnlock )
  1350.         this->ReleaseLockout();
  1351. }
  1352.  
  1353. void DialogScriptData::SetScriptAndLockKeyboard()
  1354. {
  1355. //    this->SetScriptAndLockKeyboard( FontToScript( GetAppFont() ) );
  1356.     WASSERT( FontToScript( GetSysFont()) == FontToScript( GetAppFont() ));
  1357.     this->SetScriptAndLockKeyboard( FontToScript( GetSysFont() ) );
  1358. }
  1359.  
  1360. // There are two cases we need to be aware of here when the script passed
  1361. // in comes from an existing IText* and isn't Roman.  First, it's possible
  1362. // that the keyscript is not yet set to that script (that it's still Roman).
  1363. // Second, the dialog may not be in a state to properly display that text.
  1364.  
  1365. void DialogScriptData::SetScriptAndLockKeyboard( ODScriptCode script )
  1366. {
  1367.     if ( script != smRoman )    // lock all changes out: switch to Roman will
  1368.     {                            // result in non-Roman text being garbage
  1369.         if ( GetScriptManagerVariable(smKeyScript) != script )
  1370.             KeyScript( script );    // script may not yet have been set
  1371.  
  1372.         WASSERT(fDialog);
  1373.         TEHandle teh = ((DialogPeek)fDialog)->textH;
  1374.         if ( FontToScript( (*teh)->txFont ) != script )
  1375.         {
  1376.             (*teh)->txFont = GetScriptVariable( script, smScriptSysFond );            
  1377.         }
  1378.  
  1379.         KeyScript( smKeyDisableKybdSwitch );
  1380.         fMustUnlock = kODTrue;
  1381.     }
  1382.     fScript = script;
  1383. }
  1384.  
  1385. void DialogScriptData::ReleaseLockout()
  1386. {
  1387.     if ( fMustUnlock != kODFalse )
  1388.     {
  1389.         KeyScript( smKeyEnableKybds );
  1390.         fMustUnlock = kODFalse;
  1391.     }
  1392. }
  1393.  
  1394. ODBoolean DialogScriptData::ItemRedrawn( short item )
  1395. {
  1396.     WASSERT( item < kMaxNumItems );
  1397.     return (fItemRedrawn & 1L<<(item-1)) != 0;
  1398. }
  1399.  
  1400. void DialogScriptData::SetRedrawn( short item )
  1401. {
  1402.     WASSERT( item < kMaxNumItems );
  1403.     fItemRedrawn |= 1L<<(item-1);
  1404. }
  1405.